interface ConfettiConfig {
  maxCount: number // set max confetti count
  speed: number // set the particle animation speed
  frameInterval: number // the confetti animation frame interval in milliseconds
  alpha: number // the alpha opacity of the confetti (between 0 and 1, where 1 is opaque and 0 is invisible)
  gradient: boolean // whether to use gradients for the confetti particles
}
interface Particle {
  [key: string]: any
}

const colors = [
  'rgba(30,144,255,',
  'rgba(107,142,35,',
  'rgba(255,215,0,',
  'rgba(255,192,203,',
  'rgba(106,90,205,',
  'rgba(173,216,230,',
  'rgba(238,130,238,',
  'rgba(152,251,152,',
  'rgba(70,130,180,',
  'rgba(244,164,96,',
  'rgba(210,105,30,',
  'rgba(220,20,60,',
]

class Confetti {
  #config: ConfettiConfig = {
    maxCount: 150,
    speed: 2,
    frameInterval: 15,
    alpha: 1,
    gradient: true,
  }
  #particles: any[] = []
  #context: CanvasRenderingContext2D | null = null

  constructor(config?: ConfettiConfig) {
    if (config) {
      this.#config = { ...this.#config, ...config }
    }
  }
  start(duration = 3) {
    console.log('start')
    const width = window.innerWidth
    const height = window.innerHeight
    let canvas = document.getElementById('confetti-canvas') as HTMLCanvasElement
    if (!canvas) {
      canvas = document.createElement('canvas')
      canvas.setAttribute('id', 'confetti-canvas')
      canvas.setAttribute(
        'style',
        'display:block;z-index:999999;pointer-events:none;position:fixed;top:0'
      )
      document.body.prepend(canvas)
      canvas.width = width
      canvas.height = height
      window.addEventListener(
        'resize',
        function () {
          canvas.width = window.innerWidth
          canvas.height = window.innerHeight
        },
        true
      )
      this.#context = canvas.getContext('2d')
    }
    while (this.#particles.length < this.#config.maxCount)
      this.#particles.push(this.#resetParticle({}, width, height))
    this.#runAnimation()
    if (duration) {
      setTimeout(this.stop, duration)
    }
  }
  stop() {
    console.log('stop')
  }

  #runAnimation() {
    if (!this.#context) return
    console.log('sd')
    if (!this.#particles.length) {
      this.#context.clearRect(0, 0, window.innerWidth, window.innerHeight)
    } else {
      this.#drawParticles(this.#context)
    }
  }
  #resetParticle(particle: Particle, width: number, height: number) {
    particle.color =
      colors[(Math.random() * colors.length) | 0] + (this.#config.alpha + ')')
    particle.color2 =
      colors[(Math.random() * colors.length) | 0] + (this.#config.alpha + ')')
    particle.x = Math.random() * width
    particle.y = Math.random() * height - height
    particle.diameter = Math.random() * 10 + 5
    particle.tilt = Math.random() * 10 - 10
    particle.tiltAngleIncrement = Math.random() * 0.07 + 0.05
    particle.tiltAngle = Math.random() * Math.PI
    return particle
  }

  #drawParticles(context: CanvasRenderingContext2D) {
    let x, y, x2, y2
    for (let i = 0; i < this.#particles.length; i++) {
      const particle = this.#particles[i]
      context.beginPath()
      context.lineWidth = particle.diameter
      x2 = particle.x + particle.tilt
      x = x2 + particle.diameter / 2
      y2 = particle.y + particle.tilt + particle.diameter / 2
      if (this.#config.gradient) {
        const gradient = context.createLinearGradient(x, particle.y, x2, y2)
        gradient.addColorStop(0, particle.color)
        gradient.addColorStop(1, particle.color2)
        context.strokeStyle = gradient
      } else context.strokeStyle = particle.color
      context.moveTo(x, particle.y)
      context.lineTo(x2, y2)
      context.stroke()
    }
  }
}

export default new Confetti()
